Skip to content

TGA support - #51

Merged
matmen merged 2 commits into
masterfrom
tga
Oct 15, 2026
Merged

matmen merged 2 commits into
masterfrom
tga

Conversation

@matmen

@matmen matmen commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

Adds Truevision TGA (Targa) decoding and encoding. TGA is still common for game textures, sprites and screenshots, and in 3D/VFX pipelines.

Decoding

  • Image types: color mapped, truecolor and greyscale, uncompressed or run length encoded (including packets that cross scan lines).
  • Pixel formats:
    • color maps with 8/15/16/24/32 bit entries and an offset first index
    • truecolor with 15/16/24/32 bits
    • greyscale with 8 bits, or 16 bits including alpha
  • Origins: all four (bottom/top, left/right).
  • 16 bit images: the "attribute" bit is ignored, like image-rs does. Writers fill it inconsistently (always zero, inverted alpha, or unrelated data), so these images decode as opaque.
  • Detection: TGA has no magic number, so ImageType.isTGA() / getType() === 'tga' recognize it by a consistent header or the TGA 2.0 footer. Over 2267 other image files (BMP, ICO, PSD, DDS, ...) it gave no false positives.
  • Robustness: truncated data is rejected instead of being read past the end.

Encoding

Image.encodeTGA() writes run length encoded files: 24 bit for opaque images, 32 bit otherwise. They have a top left origin and the TGA 2.0 footer, so they are easy to recognize.

Verification

  • Pillow and image-rs test files (53 TGAs):
    • 43 are pixel-identical to Pillow.
    • 6 are image-rs test files that Pillow can't read; we decode them. For the four origin variants, which store the same pixel data with different origin flags, the four decoded images are exact mirror images of each other.
    • 2 differ by design: 16 bit files where Pillow reads the attribute bit as inverted alpha.
    • 2 are broken files that both reject.
  • Encoder: our TGAs round-trip losslessly and Pillow reads them pixel-identically.
  • New tests: tests/tga.js builds TGAs byte by byte: bottom left origin with an image ID, a color map with a first index offset and top right origin, run length encoded greyscale + alpha with packets crossing scan lines, the 16 bit attribute bit, encoding round trips and truncated data.

Closes #21

@matmen matmen added this to the v3.1.0 milestone Oct 15, 2026
@matmen matmen self-assigned this Oct 15, 2026
@matmen matmen added the enhancement New feature or request label Oct 15, 2026
matmen and others added 2 commits October 15, 2026 08:30
Color mapped, truecolor and greyscale images, uncompressed and run length
encoded, all four origins. TGAs have no magic number, ImageType recognizes
them by a consistent header or the TGA 2.0 footer (no false positives over
2267 other image files). 16 bit files ignore the attribute bit like
image-rs does, writers fill it inconsistently. encodeTGA() writes run
length encoded 24 bit (opaque) or 32 bit files with the 2.0 footer.
Matches Pillow on the Pillow and image-rs test files except for that bit,
and also reads the image-rs files Pillow rejects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ljnxm1Qjrocq1izGajLx8J
the release check doesn't remove it, it would end up in the release

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ljnxm1Qjrocq1izGajLx8J
@matmen
matmen merged commit 46f7fc1 into master Oct 15, 2026
13 checks passed
@matmen
matmen deleted the tga branch October 15, 2026 08:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FR] TGA format support

1 participant